<?php

class ContentType
{
    private $xmlsource;
    private $xmltree;
    
    public function __construct($xmlsource=null)
    {
        $this->xmlsource = $xmlsource;
        $this->xmltree = null;
    }
    
    public function setXMLSource($xmlsource)
    {
        $this->xmlsource = $xmlsource;
        $this->xmltree = null;
    }
    
    public function getName()
    {
        $xmltree = $this->getXMLTree();
        return "{$xmltree->meta->name}";
    }
    
    public function getEditView($content_data)
    {
        $editview = $this->getViewTree('edit');
        if ($editview != null) {
            $template = "{$editview['template']}";
            $xslDoc = new DOMDocument();
            $xslDoc->load($template);
            
            $xmlDoc = new DOMDocument();
            $xmlDoc->loadXML($content_data);
            
            $proc = new XSLTProcessor();
            $proc->importStylesheet($xslDoc);
            return $proc->transformToXML($xmlDoc);
        } else {
            return $this->getDefaultEditView();
        }
    }
    
    public function getDisplayView($content_data)
    {
        $displayview = $this->getViewTree('display');
        if ($displayview != null) {
            $template = "{$displayview['template']}";
            $xslDoc = new DOMDocument();
            $xslDoc->load($template);
            
            $xmlDoc = new DOMDocument();
            $xmlDoc->loadXML($content_data);
            
            $proc = new XSLTProcessor();
            $proc->importStylesheet($xslDoc);
            return $proc->transformToXML($xmlDoc);
        } else {
            return $this->getDefaultEditView();
        }
    }
    
    public function getFields()
    {
        $xmltree = $this->getXMLTree();
        $fields = array();
        foreach ($xmltree->fields->field as $field) {
            if ($field['type'] == 'string') {
                $newfield = new StringField($field['name']);
            } elseif ($field['type'] == 'integer') {
                $newfield = new IntegerField($field['name']);
            } elseif ($field['type'] == 'float') {
                $newfield = new FloatField($field['name']);
            } elseif ($field['type'] == 'select') {
                $newfield = new SelectField($field['name']);
            } elseif ($field['type'] == 'multiselect') {
                $newfield = new MultiselectField($field['name']);
            } elseif ($field['type'] == 'bool') {
                $newfield = new BooleanField($field['name']);
            }
            
            if ($newfield instanceof SelectField) {
                $newfield->setOptions(explode(',', $field['options']));
            }
            
            if ($field['default']) {
                if ($newfield instanceof MultiselectField) {
                    $values = explode(',', $field['default']);
                    foreach ($values as $value) {
                        $newfield->setValue($value);
                    }
                } else {
                    $newfield->setValue($field['default']);
                }
            }
            
            if ($field['title']) {
                $newfield->setTitle($field['title']);
            }
            
            $fields[] = $newfield;
        }
        
        return $fields;
    }
    
    private function getXMLTree()
    {
        if ($this->xmltree != null) {
            return $this->xmltree;
        } else {
            //TODO: construct tree from source
        }
    }
    
    private function getViewTree($viewname)
    {
        $xmltree = $this->getXMLTree();
        $viewtree = null;
        if ($xmltree->views) {
            foreach ($xmltree->views->view as $view) {
                if ($view['type'] == $viewname) {
                    $viewtree = $view;
                }
            }
        }
        return $viewtree;
    }
    
    private function getDefaultEditView()
    {
        $ret = '';
        $fields = $this->getFields();
        foreach ($field as $field) {
            $name = $field->getName();
            $value = $field->getValue();
            $ret .= "<p><strong>$title:</strong> $value</p>\n";
        }
        return $ret;
    }
    
    private function getDefaultDisplayView()
    {
        $ret = '';
        $fields = $this->getFields();
        foreach ($field as $field) {
            $title = $field->getTitle();
            $name = $field->getName();
            $value = $field->getValue();
            $ret .= "<p><strong>$title:</strong> <input type='text' name='$name' value='$value'/></p>\n";
            // TODO: specialize the above string based on Field type
        }
        return $ret;
    }
}

abstract class Field
{
    protected $value;
    private $name;
    private $title;
    
    public function __construct($name)
    {
        $this->name = name;
    }
    
    public function getName()
    {
        return $this->name;
    }
    
    public function getValue()
    {
        return $this->value;
    }
    
    public function setTitle($title)
    {
        $this->title = $title;
    }
    
    public function getTitle()
    {
        return $this->title;
    }
}

class IntegerField extends Field
{
    public function setValue($int)
    {
        $this->value = (int)$int;
    }
}

class StringField extends Field
{
    public function setValue($str)
    {
        $this->value = $str;
    }
}

class FloatField extends Field
{
    public function setValue($float)
    {
        $this->value = (float)$float;
    }
}

class SelectField extends Field
{
    private $options;
    
    public function setOptions($options) {
        if (is_array($options)) {
            $this->options = $options;
        } else {
            $this->options = array();
        }
    }
    
    public function setValue($opt)
    {
        if (in_array($opt, $this->options)) {
            $this->value = $opt;
        }
    }
}

class MultiselectField extends SelectField
{
    private $selected_values;
    
    public function __construct($name)
    {
        $this->selected_values = array();
    }
    
    public function setValue($opt)
    {
        if (!in_array($opt, $this->selected_values) && in_array($opt, $this->options)) {
            if (count($this->selected_values) == 0) {
                $this->value = $opt;
            } else {
                $this->value .= ",$opt";
            }
            $this->selected_values[] = $opt;
        }
    }
    
    public function getValues()
    {
        return explode('', $this->value);
    }
}

class BooleanField extends Field
{
    public function setValue($bool)
    {
        if ($bool == true || $bool == 'true' || (int)$bool > 0) {
            $this->value = 'true';
        } else {
            $this->value = 'false';
        }
    }
}